library(Seurat)
library(DAAG)
library(tidyverse)
library(relaimpo)
library(bootstrap)
Read in tumor object
subset tumor seurat obeject to TN only
tn_samples <- filter(tiss_subset_tumor2@meta.data, sample_name == "LT_S34" | sample_name == "LT_S43" | sample_name == "LT_S45" | sample_name == "LT_S49" | sample_name == "LT_S52" | sample_name == "LT_S51" | sample_name == "LT_S56" | sample_name == "LT_S67" | sample_name == "LT_S69" | sample_name == "LT_S74" | sample_name == "LT_S75")
tn_seurat <- SubsetData(tiss_subset_tumor2, cells.use = tn_samples$cell_id)
rownames(tn_seurat@meta.data) <- tn_seurat@meta.data$cell_id
Investigate each Signature found from grouped analysis: 1. Alveolar Sig 2. Kynurenine Sig 3. Plasminogen Sig 4. Serpine1 5. Gap Junction Sig
- Alveolar Sig
DOR_Alveolar <- as.data.frame(FetchData(object = tn_seurat, vars.all = c("SFTPC", "SFTPB", "SFTPD", "PGC", "CLDN18", "AQP4", "SCGB3A1", "ABCA3", "GATA6", "NKX2-1", "SFTA3", "IGFBP2", "HOPX", "NAPSA", "FOXA2", "AGER", "LAMP1")))
DOR_Alveolar$cell_id <- rownames(DOR_Alveolar)
DOR_Alveolar <- merge(tn_seurat@meta.data, DOR_Alveolar, by = "cell_id")
rownames(DOR_Alveolar) <- DOR_Alveolar$cell_id
- Kynurenine Sig
DOR_Kynurenine <- as.data.frame(FetchData(object = tn_seurat, vars.all = c('IDO1', 'KYNU', 'QPRT')))
DOR_Kynurenine$cell_id <- rownames(DOR_Kynurenine)
DOR_Kynurenine <- merge(tn_seurat@meta.data, DOR_Kynurenine, by = "cell_id")
rownames(DOR_Kynurenine) <- DOR_Kynurenine$cell_id
- Plasminogen Sig
DOR_Plasminogen <- as.data.frame(FetchData(object = tn_seurat, vars.all = c('ANXA2', 'PLAT', 'PLAU', 'PLAUR')))
DOR_Plasminogen$cell_id <- rownames(DOR_Plasminogen)
DOR_Plasminogen <- merge(tn_seurat@meta.data, DOR_Plasminogen, by = "cell_id")
rownames(DOR_Plasminogen) <- DOR_Plasminogen$cell_id
- Serpine1
DOR_SERPINE1 <- as.data.frame(FetchData(object = tn_seurat, vars.all = c('SERPINE1')))
DOR_SERPINE1$cell_id <- rownames(DOR_SERPINE1)
DOR_SERPINE1 <- merge(tn_seurat@meta.data, DOR_SERPINE1, by = "cell_id")
rownames(DOR_SERPINE1) <- DOR_SERPINE1$cell_id
- Gap Junction Sig
DOR_GapJunction <- as.data.frame(FetchData(object = tn_seurat, vars.all = c('GJB3', 'GJB2', 'GJB4','GJB5')))
DOR_GapJunction$cell_id <- rownames(DOR_GapJunction)
DOR_GapJunction <- merge(tn_seurat@meta.data, DOR_GapJunction, by = "cell_id")
rownames(DOR_GapJunction) <- DOR_GapJunction$cell_id
fit 1 = Alveolar Sig
summary(fit1) # show results
Call:
lm(formula = dor ~ SFTPC + SFTPB + SFTPD + PGC + CLDN18 + AQP4 +
SCGB3A1 + ABCA3 + GATA6 + `NKX2-1` + SFTA3 + IGFBP2 + HOPX +
NAPSA + FOXA2 + AGER + LAMP1, data = DOR_Alveolar)
Residuals:
Min 1Q Median 3Q Max
-0.31790 -0.03572 0.00897 0.04640 0.19908
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.6616254 0.0056816 116.451 < 2e-16 ***
SFTPC 0.0116742 0.0063559 1.837 0.066646 .
SFTPB 0.0022941 0.0025315 0.906 0.365098
SFTPD -0.0429224 0.0107056 -4.009 6.7e-05 ***
PGC -0.0082526 0.0135026 -0.611 0.541261
CLDN18 0.0007957 0.0196329 0.041 0.967680
AQP4 -0.0040422 0.0107509 -0.376 0.707031
SCGB3A1 -0.0011107 0.0060576 -0.183 0.854568
ABCA3 -0.0034290 0.0096255 -0.356 0.721763
GATA6 -0.0226240 0.0228514 -0.990 0.322471
`NKX2-1` -0.0451323 0.0044903 -10.051 < 2e-16 ***
SFTA3 0.0054035 0.0059639 0.906 0.365205
IGFBP2 0.0330716 0.0016918 19.548 < 2e-16 ***
HOPX -0.0335134 0.0036519 -9.177 < 2e-16 ***
NAPSA -0.0302077 0.0033578 -8.996 < 2e-16 ***
FOXA2 -0.0273386 0.0044887 -6.091 1.8e-09 ***
AGER -0.0907966 0.0243912 -3.723 0.000212 ***
LAMP1 0.0030322 0.0095368 0.318 0.750610
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.071 on 745 degrees of freedom
Multiple R-squared: 0.7277, Adjusted R-squared: 0.7214
F-statistic: 117.1 on 17 and 745 DF, p-value: < 2.2e-16
fit2 = Kynurenine Sig
fit2 <- lm(dor ~ IDO1 + KYNU + QPRT, data=DOR_Kynurenine)
summary(fit2) # show results
Call:
lm(formula = dor ~ IDO1 + KYNU + QPRT, data = DOR_Kynurenine)
Residuals:
Min 1Q Median 3Q Max
-0.35619 -0.09619 -0.09157 0.15381 0.25432
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.656187 0.005075 129.289 < 2e-16 ***
IDO1 -0.025909 0.013803 -1.877 0.06089 .
KYNU 0.026314 0.009387 2.803 0.00519 **
QPRT -0.103465 0.015602 -6.631 6.31e-11 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.1303 on 759 degrees of freedom
Multiple R-squared: 0.0659, Adjusted R-squared: 0.0622
F-statistic: 17.85 on 3 and 759 DF, p-value: 3.348e-11
# diagnostic plots
plot(fit2)




ggplot(DOR_Kynurenine, aes(x = IDO1, y = dor, color = sample_name)) + geom_point()

ggplot(DOR_Kynurenine, aes(x = KYNU, y = dor, color = sample_name)) + geom_point()

ggplot(DOR_Kynurenine, aes(x = QPRT, y = dor, color = sample_name)) + geom_point()

fit3 = Plasminogen Sig
fit3 <- lm(dor ~ PLAU + PLAUR + PLAT + ANXA2, data=DOR_Plasminogen)
summary(fit3) # show results
Call:
lm(formula = dor ~ PLAU + PLAUR + PLAT + ANXA2, data = DOR_Plasminogen)
Residuals:
Min 1Q Median 3Q Max
-0.39284 -0.07108 0.02876 0.07998 0.24803
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.515175 0.013690 37.631 < 2e-16 ***
PLAU -0.026385 0.004716 -5.595 3.08e-08 ***
PLAUR -0.031850 0.006093 -5.227 2.22e-07 ***
PLAT -0.043839 0.003904 -11.229 < 2e-16 ***
ANXA2 0.056471 0.003923 14.393 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.1065 on 758 degrees of freedom
Multiple R-squared: 0.3766, Adjusted R-squared: 0.3733
F-statistic: 114.5 on 4 and 758 DF, p-value: < 2.2e-16
# diagnostic plots
plot(fit3)




ggplot(DOR_Plasminogen, aes(x = PLAU, y = dor, color = sample_name)) + geom_point()

ggplot(DOR_Plasminogen, aes(x = PLAUR, y = dor, color = sample_name)) + geom_point()

ggplot(DOR_Plasminogen, aes(x = PLAT, y = dor, color = sample_name)) + geom_point()

ggplot(DOR_Plasminogen, aes(x = ANXA2, y = dor, color = sample_name)) + geom_point()

fit4 = SERPINE1
fit4 <- lm(dor ~ SERPINE1, data=DOR_SERPINE1)
summary(fit4) # show results
Call:
lm(formula = dor ~ SERPINE1, data = DOR_SERPINE1)
Residuals:
Min 1Q Median 3Q Max
-0.36405 -0.10405 -0.04199 0.14595 0.25223
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.664046 0.005113 129.880 < 2e-16 ***
SERPINE1 -0.047593 0.007384 -6.446 2.04e-10 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.1311 on 761 degrees of freedom
Multiple R-squared: 0.05177, Adjusted R-squared: 0.05052
F-statistic: 41.55 on 1 and 761 DF, p-value: 2.042e-10
# diagnostic plots
plot(fit4)




ggplot(DOR_SERPINE1, aes(x = SERPINE1, y = dor, color = sample_name)) + geom_point()

fit5 = Gap Junction Sig
fit5 <- lm(dor ~ GJB3 + GJB2 + GJB4 + GJB5, data=DOR_GapJunction)
summary(fit5) # show results
Call:
lm(formula = dor ~ GJB3 + GJB2 + GJB4 + GJB5, data = DOR_GapJunction)
Residuals:
Min 1Q Median 3Q Max
-0.33107 -0.07003 -0.07003 0.14248 0.17997
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.630034 0.004815 130.836 < 2e-16 ***
GJB3 0.029685 0.018856 1.574 0.1158
GJB2 0.042758 0.023258 1.838 0.0664 .
GJB4 0.102237 0.016175 6.321 4.44e-10 ***
GJB5 0.124777 0.014473 8.622 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.1227 on 758 degrees of freedom
Multiple R-squared: 0.1722, Adjusted R-squared: 0.1678
F-statistic: 39.42 on 4 and 758 DF, p-value: < 2.2e-16
# diagnostic plots
plot(fit5)




ggplot(DOR_GapJunction, aes(x = GJB2, y = dor, color = sample_name)) + geom_point()

ggplot(DOR_GapJunction, aes(x = GJB3, y = dor, color = sample_name)) + geom_point()

ggplot(DOR_GapJunction, aes(x = GJB4, y = dor, color = sample_name)) + geom_point()

ggplot(DOR_GapJunction, aes(x = GJB5, y = dor, color = sample_name)) + geom_point()

# # K-fold cross-validation
# cv.lm(data = DOR_GapJunction, form.lm = fit5, m = 10, plotit = FALSE)
# # Assessing R2 shrinkage using 10-Fold Cross-Validation
# # define functions
# theta.fit <- function(x,y){lsfit(x,y)}
# theta.predict <- function(fit5,x){cbind(1,x)%*%fit5$coef}
#
# # matrix of predictors
# X <- as.matrix(DOR_GapJunction[c("GJB3","GJB2","GJB4","GJB5")])
# # vector of predicted values
# y <- as.matrix(DOR_GapJunction[c("dor")])
#
# results <- crossval(X,y,theta.fit,theta.predict,ngroup=10)
# cor(y, fit5$fitted.values)**2 # raw R2
# cor(y,results$cv.fit5)**2 # cross-validated R2
#
# # Calculate Relative Importance for Each Predictor
# calc.relimp(fit5,type = c("lmg","last","first","pratt"), rela=TRUE)
# # Bootstrap Measures of Relative Importance (1000 samples)
# boot <- boot.relimp(fit5, b = 1000, type = c("lmg", "last", "first", "pratt"), rank = TRUE, diff = TRUE, rela = TRUE)
# booteval.relimp(boot) # print result
# plot(booteval.relimp(boot,sort=TRUE)) # plot result
table(tn_seurat@meta.data$biopsy_site, tn_seurat@meta.data$dor)
0.3 0.31 0.43 0.46 0.5 0.56 0.57 0.7 0.81
Adrenal 0 1 0 0 0 0 0 0 0
Brain 0 0 0 0 0 0 0 0 0
Liver 0 0 0 0 0 0 0 28 0
LN 0 0 5 0 6 305 16 0 0
Lung 14 0 0 0 0 71 0 0 293
Pleura 0 0 0 24 0 0 0 0 0
table(tn_seurat@meta.data$sample_name, tn_seurat@meta.data$dor)
0.3 0.31 0.43 0.46 0.5 0.56 0.57 0.7 0.81
LT_S34 0 0 0 24 0 0 0 0 0
LT_S43 0 0 5 0 0 0 0 0 0
LT_S45 0 1 0 0 0 0 0 0 0
LT_S49 0 0 0 0 6 0 0 0 0
LT_S51 0 0 0 0 0 0 16 0 0
LT_S52 14 0 0 0 0 0 0 0 0
LT_S56 0 0 0 0 0 0 0 0 291
LT_S67 0 0 0 0 0 0 0 0 2
LT_S69 0 0 0 0 0 305 0 0 0
LT_S74 0 0 0 0 0 71 0 0 0
LT_S75 0 0 0 0 0 0 0 28 0
table(tn_seurat@meta.data$sample_name)
LT_S34 LT_S43 LT_S45 LT_S49 LT_S51 LT_S52 LT_S56 LT_S67 LT_S69 LT_S74 LT_S75
24 5 1 6 16 14 291 2 305 71 28
Bulkize the samples
tn_seurat <- SetIdent(tn_seurat, ident.use = tn_seurat@meta.data$sample_name)
table(tn_seurat@ident)
LT_S34 LT_S43 LT_S45 LT_S49 LT_S51 LT_S52 LT_S56 LT_S67 LT_S69 LT_S74 LT_S75
24 5 1 6 16 14 291 2 305 71 28
sample.averages <- AverageExpression(object = tn_seurat)
Finished averaging RNA for cluster LT_S34
Finished averaging RNA for cluster LT_S43
Finished averaging RNA for cluster LT_S45
Finished averaging RNA for cluster LT_S49
Finished averaging RNA for cluster LT_S51
Finished averaging RNA for cluster LT_S52
Finished averaging RNA for cluster LT_S56
Finished averaging RNA for cluster LT_S67
Finished averaging RNA for cluster LT_S69
Finished averaging RNA for cluster LT_S74
Finished averaging RNA for cluster LT_S75
To find DE genes between bulkized TN samples with low and high DOR, export table with groups
# set up table
sample.averages.t <- as.data.frame(t(sample.averages))
head(sample.averages.t)
sample.averages.t$sample_name <- rownames(sample.averages.t)
sample.averages.t <- left_join(sample.averages.t, dor_meta, by = "sample_name")
rownames(sample.averages.t) <- sample.averages.t$sample_name
length(colnames(sample.averages.t))
[1] 26489
DE_avg <- pairwise.wilcox.test(x = sample.averages.t$EGFR, g = sample.averages.t$dor_class)
write.csv(sample.averages.t, file = "/myVolume/TN_bulkized_data.csv")
TN.sample.averages <- sample.averages
head(TN.sample.averages)
Bulkize fit analysis Alveolar

Bulkize fit analysis Kynurenine

Bulkize fit analysis Plasminogen

Bulkize fit analysis of SERPINE1

Bulkize fit analysis GapJunction

bulkized_TN_markers <- read.csv(file = paste(dir, "Data_input/mwu_luad.csv", sep = ""))
bulkized_TN_markers.f <- filter(bulkized_TN_markers, pval_1 <= 0.05)
hist(bulkized_TN_markers.f$stat_1)

length(bulkized_TN_markers.f$pval_1)
[1] 4115
bulkized_TN_markers.f <- bulkized_TN_markers.f[order(bulkized_TN_markers.f$stat_1, decreasing = FALSE), ]
Most compelling high expression corr to low dor
ggplot(sample.averages.t, aes(x = ADAR, y = dor)) + geom_point(aes(color = patient_id))

ggplot(sample.averages.t, aes(x = CFL1, y = dor)) + geom_point(aes(color = patient_id))

Most compelling high expression corr to high dor
ggplot(sample.averages.t, aes(x = TTLL13P, y = dor)) + geom_point(aes(color = dor_class))

ggplot(sample.averages.t, aes(x = ALS2, y = dor)) + geom_point(aes(color = dor_class))

ggplot(sample.averages.t, aes(x = RLN1, y = dor)) + geom_point(aes(color = dor_class))

ggplot(sample.averages.t, aes(x = USP45, y = dor)) + geom_point(aes(color = dor_class))

ggplot(sample.averages.t, aes(x = BDKRB1, y = dor)) + geom_point(aes(color = dor_class))

ggplot(sample.averages.t, aes(x = LINC01061, y = dor)) + geom_point(aes(color = dor_class))

ggplot(sample.averages.t, aes(x = ZNF563, y = dor)) + geom_point(aes(color = dor_class))

ggplot(sample.averages.t, aes(x = WDR19, y = dor)) + geom_point(aes(color = dor_class))

LS0tCnRpdGxlOiAiUmVncmVzc2lvbiBvZiBDbGluaWNhbCBPdXRjb21lcyB0byBTaWdzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7cn0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoREFBRykKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocmVsYWltcG8pCmxpYnJhcnkoYm9vdHN0cmFwKQpgYGAKClJlYWQgaW4gdHVtb3Igb2JqZWN0CmBgYHtyfQojIHJtKGxpc3Q9bHMoKSkKZGlyIDwtICIvbXlWb2x1bWUvc2NlbGxfbHVuZ19hZGVub2NhcmNpbm9tYS8iCmxvYWQoZmlsZSA9IHBhc3RlKGRpciwgIkRhdGFfaW5wdXQvb2JqZWN0cy9OSTA0X3R1bW9yX3NldXJhdF9vYmplY3QuUkRhdGEiLCBzZXAgPSAiIikpCgojUmVhZCBpbiBkZXB0aCBvZiByZXNwb25zZSBjbGluaWNhbCBvdXRjb21lcwpkb3JfbWV0YSA8LSByZWFkLmNzdihmaWxlID0gcGFzdGUoZGlyLCAiRGF0YV9pbnB1dC9jc3ZfZmlsZXMvZGVwdGhvZnJlc3BvbnNlX3RuLmNzdiIsIHNlcCA9ICIiKSkKI2NvcnJlY3QgbWlzYW5ub2F0aW9uIGluIGRvcgpkb3JfbWV0YSRzYW1wbGVfbmFtZSA8LSBnc3ViKHBhdHRlcm4gPSAiTFRfUzU3IiwgcmVwbGFjZW1lbnQgPSAiTFRfUzUxIiwgeCA9IGRvcl9tZXRhJHNhbXBsZV9uYW1lKQpkb3JfbWV0YSRkb3IgPC0gZ3N1YihwYXR0ZXJuID0gIi4xMiIsIHJlcGxhY2VtZW50ID0gIi40NiIsIHggPSBkb3JfbWV0YSRkb3IpCmRvcl9tZXRhJGRvcl9jbGFzcyA8LSBjKCJsb3ciLCAibG93IiwgImxvdyIsICJsb3ciLCAibG93IiwgImhpZ2giLCAiaGlnaCIsICJoaWdoIiwgImhpZ2giLCAiaGlnaCIsICJoaWdoIikKZG9yX21ldGEKYGBgCgpzdWJzZXQgdHVtb3Igc2V1cmF0IG9iZWplY3QgdG8gVE4gb25seQpgYGB7cn0KdG5fc2FtcGxlcyA8LSBmaWx0ZXIodGlzc19zdWJzZXRfdHVtb3IyQG1ldGEuZGF0YSwgc2FtcGxlX25hbWUgPT0gIkxUX1MzNCIgfCBzYW1wbGVfbmFtZSA9PSAiTFRfUzQzIiB8IHNhbXBsZV9uYW1lID09ICJMVF9TNDUiIHwgc2FtcGxlX25hbWUgPT0gIkxUX1M0OSIgfCBzYW1wbGVfbmFtZSA9PSAiTFRfUzUyIiB8IHNhbXBsZV9uYW1lID09ICJMVF9TNTEiIHwgc2FtcGxlX25hbWUgPT0gIkxUX1M1NiIgfCBzYW1wbGVfbmFtZSA9PSAiTFRfUzY3IiB8IHNhbXBsZV9uYW1lID09ICJMVF9TNjkiIHwgc2FtcGxlX25hbWUgPT0gIkxUX1M3NCIgfCBzYW1wbGVfbmFtZSA9PSAiTFRfUzc1IikKCnRuX3NldXJhdCA8LSBTdWJzZXREYXRhKHRpc3Nfc3Vic2V0X3R1bW9yMiwgY2VsbHMudXNlID0gdG5fc2FtcGxlcyRjZWxsX2lkKQpyb3duYW1lcyh0bl9zZXVyYXRAbWV0YS5kYXRhKSA8LSB0bl9zZXVyYXRAbWV0YS5kYXRhJGNlbGxfaWQKYGBgCgoKYGBge3J9CnRuX3NldXJhdEBtZXRhLmRhdGEgPC0gbWVyZ2UoZG9yX21ldGFbLGMoMjo0KV0sIHRuX3NldXJhdEBtZXRhLmRhdGEsIGJ5ID0gInNhbXBsZV9uYW1lIikKcm93bmFtZXModG5fc2V1cmF0QG1ldGEuZGF0YSkgPC0gdG5fc2V1cmF0QG1ldGEuZGF0YSRjZWxsX2lkCmBgYAoKCkludmVzdGlnYXRlIGVhY2ggU2lnbmF0dXJlIGZvdW5kIGZyb20gZ3JvdXBlZCBhbmFseXNpczoKMS4gQWx2ZW9sYXIgU2lnCjIuIEt5bnVyZW5pbmUgU2lnCjMuIFBsYXNtaW5vZ2VuIFNpZwo0LiBTZXJwaW5lMQo1LiBHYXAgSnVuY3Rpb24gU2lnCgoxLiBBbHZlb2xhciBTaWcKYGBge3J9CkRPUl9BbHZlb2xhciA8LSBhcy5kYXRhLmZyYW1lKEZldGNoRGF0YShvYmplY3QgPSB0bl9zZXVyYXQsIHZhcnMuYWxsID0gYygiU0ZUUEMiLCAiU0ZUUEIiLCAiU0ZUUEQiLCAiUEdDIiwgIkNMRE4xOCIsICJBUVA0IiwgIlNDR0IzQTEiLCAiQUJDQTMiLCAiR0FUQTYiLCAiTktYMi0xIiwgIlNGVEEzIiwgIklHRkJQMiIsICJIT1BYIiwgIk5BUFNBIiwgIkZPWEEyIiwgIkFHRVIiLCAiTEFNUDEiKSkpCkRPUl9BbHZlb2xhciRjZWxsX2lkIDwtIHJvd25hbWVzKERPUl9BbHZlb2xhcikKRE9SX0FsdmVvbGFyIDwtIG1lcmdlKHRuX3NldXJhdEBtZXRhLmRhdGEsIERPUl9BbHZlb2xhciwgYnkgPSAiY2VsbF9pZCIpCnJvd25hbWVzKERPUl9BbHZlb2xhcikgPC0gRE9SX0FsdmVvbGFyJGNlbGxfaWQKYGBgCgoyLiBLeW51cmVuaW5lIFNpZwpgYGB7cn0KRE9SX0t5bnVyZW5pbmUgPC0gYXMuZGF0YS5mcmFtZShGZXRjaERhdGEob2JqZWN0ID0gdG5fc2V1cmF0LCB2YXJzLmFsbCA9IGMoJ0lETzEnLCAnS1lOVScsICdRUFJUJykpKQpET1JfS3ludXJlbmluZSRjZWxsX2lkIDwtIHJvd25hbWVzKERPUl9LeW51cmVuaW5lKQpET1JfS3ludXJlbmluZSA8LSBtZXJnZSh0bl9zZXVyYXRAbWV0YS5kYXRhLCBET1JfS3ludXJlbmluZSwgYnkgPSAiY2VsbF9pZCIpCnJvd25hbWVzKERPUl9LeW51cmVuaW5lKSA8LSBET1JfS3ludXJlbmluZSRjZWxsX2lkCmBgYAoKMy4gUGxhc21pbm9nZW4gU2lnCmBgYHtyfQpET1JfUGxhc21pbm9nZW4gPC0gYXMuZGF0YS5mcmFtZShGZXRjaERhdGEob2JqZWN0ID0gdG5fc2V1cmF0LCB2YXJzLmFsbCA9IGMoJ0FOWEEyJywgJ1BMQVQnLCAnUExBVScsICdQTEFVUicpKSkKRE9SX1BsYXNtaW5vZ2VuJGNlbGxfaWQgPC0gcm93bmFtZXMoRE9SX1BsYXNtaW5vZ2VuKQpET1JfUGxhc21pbm9nZW4gPC0gbWVyZ2UodG5fc2V1cmF0QG1ldGEuZGF0YSwgRE9SX1BsYXNtaW5vZ2VuLCBieSA9ICJjZWxsX2lkIikKcm93bmFtZXMoRE9SX1BsYXNtaW5vZ2VuKSA8LSBET1JfUGxhc21pbm9nZW4kY2VsbF9pZApgYGAKCjQuIFNlcnBpbmUxCmBgYHtyfQpET1JfU0VSUElORTEgPC0gYXMuZGF0YS5mcmFtZShGZXRjaERhdGEob2JqZWN0ID0gdG5fc2V1cmF0LCB2YXJzLmFsbCA9IGMoJ1NFUlBJTkUxJykpKQpET1JfU0VSUElORTEkY2VsbF9pZCA8LSByb3duYW1lcyhET1JfU0VSUElORTEpCkRPUl9TRVJQSU5FMSA8LSBtZXJnZSh0bl9zZXVyYXRAbWV0YS5kYXRhLCBET1JfU0VSUElORTEsIGJ5ID0gImNlbGxfaWQiKQpyb3duYW1lcyhET1JfU0VSUElORTEpIDwtIERPUl9TRVJQSU5FMSRjZWxsX2lkCmBgYAoKNS4gR2FwIEp1bmN0aW9uIFNpZwpgYGB7cn0KRE9SX0dhcEp1bmN0aW9uIDwtIGFzLmRhdGEuZnJhbWUoRmV0Y2hEYXRhKG9iamVjdCA9IHRuX3NldXJhdCwgdmFycy5hbGwgPSBjKCdHSkIzJywgJ0dKQjInLCAnR0pCNCcsJ0dKQjUnKSkpCkRPUl9HYXBKdW5jdGlvbiRjZWxsX2lkIDwtIHJvd25hbWVzKERPUl9HYXBKdW5jdGlvbikKRE9SX0dhcEp1bmN0aW9uIDwtIG1lcmdlKHRuX3NldXJhdEBtZXRhLmRhdGEsIERPUl9HYXBKdW5jdGlvbiwgYnkgPSAiY2VsbF9pZCIpCnJvd25hbWVzKERPUl9HYXBKdW5jdGlvbikgPC0gRE9SX0dhcEp1bmN0aW9uJGNlbGxfaWQKYGBgCgpmaXQgMSA9IEFsdmVvbGFyIFNpZwpgYGB7cn0KZml0MSA8LSBsbShkb3IgfiBTRlRQQyArU0ZUUEIgKyBTRlRQRCArIFBHQyArIENMRE4xOCArIEFRUDQgKyBTQ0dCM0ExICsgQUJDQTMgKyBHQVRBNiArIGBOS1gyLTFgICsgU0ZUQTMgKyBJR0ZCUDIrIEhPUFggKyBOQVBTQSArIEZPWEEyICsgQUdFUiArIExBTVAxLCBkYXRhPURPUl9BbHZlb2xhcikKc3VtbWFyeShmaXQxKSAjIHNob3cgcmVzdWx0cwoKIyBkaWFnbm9zdGljIHBsb3RzCnBsb3QoZml0MSkKCmdncGxvdChET1JfQWx2ZW9sYXIsIGFlcyh4ID0gYE5LWDItMWAsIHkgPSBkb3IsIGNvbG9yID0gc2FtcGxlX25hbWUpKSArIGdlb21fcG9pbnQoKQpnZ3Bsb3QoRE9SX0FsdmVvbGFyLCBhZXMoeCA9IElHRkJQMiwgeSA9IGRvciwgY29sb3IgPSBzYW1wbGVfbmFtZSkpICsgZ2VvbV9wb2ludCgpCmdncGxvdChET1JfQWx2ZW9sYXIsIGFlcyh4ID0gSE9QWCwgeSA9IGRvciwgY29sb3IgPSBzYW1wbGVfbmFtZSkpICsgZ2VvbV9wb2ludCgpCmdncGxvdChET1JfQWx2ZW9sYXIsIGFlcyh4ID0gTkFQU0EsIHkgPSBkb3IsIGNvbG9yID0gc2FtcGxlX25hbWUpKSArIGdlb21fcG9pbnQoKQpnZ3Bsb3QoRE9SX0FsdmVvbGFyLCBhZXMoeCA9IEZPWEEyLCB5ID0gZG9yLCBjb2xvciA9IHNhbXBsZV9uYW1lKSkgKyBnZW9tX3BvaW50KCkKYGBgCgpmaXQyID0gS3ludXJlbmluZSBTaWcKYGBge3J9CmZpdDIgPC0gbG0oZG9yIH4gSURPMSArIEtZTlUgKyBRUFJULCBkYXRhPURPUl9LeW51cmVuaW5lKQpzdW1tYXJ5KGZpdDIpICMgc2hvdyByZXN1bHRzCgojIGRpYWdub3N0aWMgcGxvdHMgCnBsb3QoZml0MikKCmdncGxvdChET1JfS3ludXJlbmluZSwgYWVzKHggPSBJRE8xLCB5ID0gZG9yLCBjb2xvciA9IHNhbXBsZV9uYW1lKSkgKyBnZW9tX3BvaW50KCkKZ2dwbG90KERPUl9LeW51cmVuaW5lLCBhZXMoeCA9IEtZTlUsIHkgPSBkb3IsIGNvbG9yID0gc2FtcGxlX25hbWUpKSArIGdlb21fcG9pbnQoKQpnZ3Bsb3QoRE9SX0t5bnVyZW5pbmUsIGFlcyh4ID0gUVBSVCwgeSA9IGRvciwgY29sb3IgPSBzYW1wbGVfbmFtZSkpICsgZ2VvbV9wb2ludCgpCmBgYAoKZml0MyA9IFBsYXNtaW5vZ2VuIFNpZwpgYGB7cn0KZml0MyA8LSBsbShkb3IgfiBQTEFVICsgUExBVVIgKyBQTEFUICsgQU5YQTIsIGRhdGE9RE9SX1BsYXNtaW5vZ2VuKQpzdW1tYXJ5KGZpdDMpICMgc2hvdyByZXN1bHRzCgojIGRpYWdub3N0aWMgcGxvdHMgCnBsb3QoZml0MykKCmdncGxvdChET1JfUGxhc21pbm9nZW4sIGFlcyh4ID0gUExBVSwgeSA9IGRvciwgY29sb3IgPSBzYW1wbGVfbmFtZSkpICsgZ2VvbV9wb2ludCgpCmdncGxvdChET1JfUGxhc21pbm9nZW4sIGFlcyh4ID0gUExBVVIsIHkgPSBkb3IsIGNvbG9yID0gc2FtcGxlX25hbWUpKSArIGdlb21fcG9pbnQoKQpnZ3Bsb3QoRE9SX1BsYXNtaW5vZ2VuLCBhZXMoeCA9IFBMQVQsIHkgPSBkb3IsIGNvbG9yID0gc2FtcGxlX25hbWUpKSArIGdlb21fcG9pbnQoKQpnZ3Bsb3QoRE9SX1BsYXNtaW5vZ2VuLCBhZXMoeCA9IEFOWEEyLCB5ID0gZG9yLCBjb2xvciA9IHNhbXBsZV9uYW1lKSkgKyBnZW9tX3BvaW50KCkKYGBgCgpmaXQ0ID0gU0VSUElORTEKYGBge3J9CmZpdDQgPC0gbG0oZG9yIH4gU0VSUElORTEsIGRhdGE9RE9SX1NFUlBJTkUxKQpzdW1tYXJ5KGZpdDQpICMgc2hvdyByZXN1bHRzCgojIGRpYWdub3N0aWMgcGxvdHMgCnBsb3QoZml0NCkKCmdncGxvdChET1JfU0VSUElORTEsIGFlcyh4ID0gU0VSUElORTEsIHkgPSBkb3IsIGNvbG9yID0gc2FtcGxlX25hbWUpKSArIGdlb21fcG9pbnQoKQpgYGAKCmZpdDUgPSBHYXAgSnVuY3Rpb24gU2lnCmBgYHtyfQpmaXQ1IDwtIGxtKGRvciB+IEdKQjMgKyBHSkIyICsgR0pCNCArIEdKQjUsIGRhdGE9RE9SX0dhcEp1bmN0aW9uKQpzdW1tYXJ5KGZpdDUpICMgc2hvdyByZXN1bHRzCgojIGRpYWdub3N0aWMgcGxvdHMgCnBsb3QoZml0NSkKCmdncGxvdChET1JfR2FwSnVuY3Rpb24sIGFlcyh4ID0gR0pCMiwgeSA9IGRvciwgY29sb3IgPSBzYW1wbGVfbmFtZSkpICsgZ2VvbV9wb2ludCgpCmdncGxvdChET1JfR2FwSnVuY3Rpb24sIGFlcyh4ID0gR0pCMywgeSA9IGRvciwgY29sb3IgPSBzYW1wbGVfbmFtZSkpICsgZ2VvbV9wb2ludCgpCmdncGxvdChET1JfR2FwSnVuY3Rpb24sIGFlcyh4ID0gR0pCNCwgeSA9IGRvciwgY29sb3IgPSBzYW1wbGVfbmFtZSkpICsgZ2VvbV9wb2ludCgpCmdncGxvdChET1JfR2FwSnVuY3Rpb24sIGFlcyh4ID0gR0pCNSwgeSA9IGRvciwgY29sb3IgPSBzYW1wbGVfbmFtZSkpICsgZ2VvbV9wb2ludCgpCgojICMgSy1mb2xkIGNyb3NzLXZhbGlkYXRpb24KIyBjdi5sbShkYXRhID0gRE9SX0dhcEp1bmN0aW9uLCBmb3JtLmxtID0gZml0NSwgbSA9IDEwLCBwbG90aXQgPSBGQUxTRSkKIyAjIEFzc2Vzc2luZyBSMiBzaHJpbmthZ2UgdXNpbmcgMTAtRm9sZCBDcm9zcy1WYWxpZGF0aW9uIAojICMgZGVmaW5lIGZ1bmN0aW9ucyAKIyB0aGV0YS5maXQgPC0gZnVuY3Rpb24oeCx5KXtsc2ZpdCh4LHkpfQojIHRoZXRhLnByZWRpY3QgPC0gZnVuY3Rpb24oZml0NSx4KXtjYmluZCgxLHgpJSolZml0NSRjb2VmfSAKIyAKIyAjIG1hdHJpeCBvZiBwcmVkaWN0b3JzCiMgWCA8LSBhcy5tYXRyaXgoRE9SX0dhcEp1bmN0aW9uW2MoIkdKQjMiLCJHSkIyIiwiR0pCNCIsIkdKQjUiKV0pCiMgIyB2ZWN0b3Igb2YgcHJlZGljdGVkIHZhbHVlcwojIHkgPC0gYXMubWF0cml4KERPUl9HYXBKdW5jdGlvbltjKCJkb3IiKV0pIAojIAojIHJlc3VsdHMgPC0gY3Jvc3N2YWwoWCx5LHRoZXRhLmZpdCx0aGV0YS5wcmVkaWN0LG5ncm91cD0xMCkKIyBjb3IoeSwgZml0NSRmaXR0ZWQudmFsdWVzKSoqMiAjIHJhdyBSMiAKIyBjb3IoeSxyZXN1bHRzJGN2LmZpdDUpKioyICMgY3Jvc3MtdmFsaWRhdGVkIFIyCiMgCiMgIyBDYWxjdWxhdGUgUmVsYXRpdmUgSW1wb3J0YW5jZSBmb3IgRWFjaCBQcmVkaWN0b3IKIyBjYWxjLnJlbGltcChmaXQ1LHR5cGUgPSBjKCJsbWciLCJsYXN0IiwiZmlyc3QiLCJwcmF0dCIpLCByZWxhPVRSVUUpCiMgIyBCb290c3RyYXAgTWVhc3VyZXMgb2YgUmVsYXRpdmUgSW1wb3J0YW5jZSAoMTAwMCBzYW1wbGVzKSAKIyBib290IDwtIGJvb3QucmVsaW1wKGZpdDUsIGIgPSAxMDAwLCB0eXBlID0gYygibG1nIiwgImxhc3QiLCAiZmlyc3QiLCAicHJhdHQiKSwgcmFuayA9IFRSVUUsIGRpZmYgPSBUUlVFLCByZWxhID0gVFJVRSkKIyBib290ZXZhbC5yZWxpbXAoYm9vdCkgIyBwcmludCByZXN1bHQKIyBwbG90KGJvb3RldmFsLnJlbGltcChib290LHNvcnQ9VFJVRSkpICMgcGxvdCByZXN1bHQKYGBgCgpgYGB7cn0KdGFibGUodG5fc2V1cmF0QG1ldGEuZGF0YSRiaW9wc3lfc2l0ZSwgdG5fc2V1cmF0QG1ldGEuZGF0YSRkb3IpCnRhYmxlKHRuX3NldXJhdEBtZXRhLmRhdGEkc2FtcGxlX25hbWUsIHRuX3NldXJhdEBtZXRhLmRhdGEkZG9yKQp0YWJsZSh0bl9zZXVyYXRAbWV0YS5kYXRhJHNhbXBsZV9uYW1lKQpgYGAKCkJ1bGtpemUgdGhlIHNhbXBsZXMKYGBge3J9CnRuX3NldXJhdCA8LSBTZXRJZGVudCh0bl9zZXVyYXQsIGlkZW50LnVzZSA9IHRuX3NldXJhdEBtZXRhLmRhdGEkc2FtcGxlX25hbWUpCnRhYmxlKHRuX3NldXJhdEBpZGVudCkKc2FtcGxlLmF2ZXJhZ2VzIDwtIEF2ZXJhZ2VFeHByZXNzaW9uKG9iamVjdCA9IHRuX3NldXJhdCkKYGBgCgpUbyBmaW5kIERFIGdlbmVzIGJldHdlZW4gYnVsa2l6ZWQgVE4gc2FtcGxlcyB3aXRoIGxvdyBhbmQgaGlnaCBET1IsIGV4cG9ydCB0YWJsZSB3aXRoIGdyb3VwcwpgYGB7cn0KIyBzZXQgdXAgdGFibGUgCnNhbXBsZS5hdmVyYWdlcy50IDwtIGFzLmRhdGEuZnJhbWUodChzYW1wbGUuYXZlcmFnZXMpKQpoZWFkKHNhbXBsZS5hdmVyYWdlcy50KQpzYW1wbGUuYXZlcmFnZXMudCRzYW1wbGVfbmFtZSA8LSByb3duYW1lcyhzYW1wbGUuYXZlcmFnZXMudCkKc2FtcGxlLmF2ZXJhZ2VzLnQgPC0gbGVmdF9qb2luKHNhbXBsZS5hdmVyYWdlcy50LCBkb3JfbWV0YSwgYnkgPSAic2FtcGxlX25hbWUiKQpyb3duYW1lcyhzYW1wbGUuYXZlcmFnZXMudCkgPC0gc2FtcGxlLmF2ZXJhZ2VzLnQkc2FtcGxlX25hbWUKCmxlbmd0aChjb2xuYW1lcyhzYW1wbGUuYXZlcmFnZXMudCkpCkRFX2F2ZyA8LSBwYWlyd2lzZS53aWxjb3gudGVzdCh4ID0gc2FtcGxlLmF2ZXJhZ2VzLnQkRUdGUiwgZyA9IHNhbXBsZS5hdmVyYWdlcy50JGRvcl9jbGFzcykKd3JpdGUuY3N2KHNhbXBsZS5hdmVyYWdlcy50LCBmaWxlID0gIi9teVZvbHVtZS9UTl9idWxraXplZF9kYXRhLmNzdiIpClROLnNhbXBsZS5hdmVyYWdlcyA8LSBzYW1wbGUuYXZlcmFnZXMKaGVhZChUTi5zYW1wbGUuYXZlcmFnZXMpCmBgYAoKCkJ1bGtpemUgZml0IGFuYWx5c2lzIEFsdmVvbGFyCmBgYHtyfQpBbHZlb2xhcl9zaWcgPC0gYygiU0ZUUEMiLCAiU0ZUUEIiLCAiU0ZUUEQiLCAiUEdDIiwgIkNMRE4xOCIsICJBUVA0IiwgIlNDR0IzQTEiLCAiQUJDQTMiLCAiR0FUQTYiLCAiTktYMi0xIiwgIlNGVEEzIiwgIklHRkJQMiIsICJIT1BYIiwgIk5BUFNBIiwgIkZPWEEyIiwgIkFHRVIiLCAiTEFNUDEiKQpUTl9BbHZlb2xhciA8LSBUTi5zYW1wbGUuYXZlcmFnZXNbQWx2ZW9sYXJfc2lnLCBdClROX0FsdmVvbGFyX21lYW4gPC0gYXMuZGF0YS5mcmFtZShjb2xNZWFucyhUTl9BbHZlb2xhcikpClROX0FsdmVvbGFyX21lYW4kc2FtcGxlX25hbWUgPC0gcm93bmFtZXMoVE5fQWx2ZW9sYXJfbWVhbikKVE5fQWx2ZW9sYXJfbWVhbiA8LSBsZWZ0X2pvaW4oVE5fQWx2ZW9sYXJfbWVhbiwgZG9yX21ldGEsIGJ5ID0gInNhbXBsZV9uYW1lIikKcm93bmFtZXMoVE5fQWx2ZW9sYXJfbWVhbikgPC0gVE5fQWx2ZW9sYXJfbWVhbiRzYW1wbGVfbmFtZQoKVE5fQWx2ZW9sYXJfZml0IDwtIGxtKGRvciB+IGNvbE1lYW5zKFROX0FsdmVvbGFyKSwgZGF0YT0gVE5fQWx2ZW9sYXJfbWVhbikKc3VtbWFyeShUTl9BbHZlb2xhcl9maXQpClROX0FsdmVvbGFyX21lYW4kcHJlZGxtIDwtIHByZWRpY3QoVE5fQWx2ZW9sYXJfZml0KQoKZ2dwX1ROX0FsdmVvbGFyIDwtIGdncGxvdChUTl9BbHZlb2xhcl9tZWFuLCBhZXMoeCA9IGNvbE1lYW5zKFROX0FsdmVvbGFyKSwgeSA9IGRvciwgY29sb3IgPSBkb3JfY2xhc3MpKSArIGdlb21fcG9pbnQoKQoKZ2dzYXZlKGdncF9UTl9BbHZlb2xhciwgZmlsZW5hbWUgPSBwYXN0ZShkaXIsICJwbG90X291dC9OSTA4L1ROX0FsdmVvbGFyX2J1bGtpemVkLnBkZiIsIHNlcCA9ICIiKSkKYGBgCgpCdWxraXplIGZpdCBhbmFseXNpcyBLeW51cmVuaW5lCmBgYHtyfQpLeW51cmVuaW5lX3NpZyA8LSBjKCdJRE8xJywgJ0tZTlUnLCAnUVBSVCcpClROX0t5bnVyZW5pbmUgPC0gVE4uc2FtcGxlLmF2ZXJhZ2VzW0t5bnVyZW5pbmVfc2lnLCBdClROX0t5bnVyZW5pbmVfbWVhbiA8LSBhcy5kYXRhLmZyYW1lKGNvbE1lYW5zKFROX0t5bnVyZW5pbmUpKQpUTl9LeW51cmVuaW5lX21lYW4kc2FtcGxlX25hbWUgPC0gcm93bmFtZXMoVE5fS3ludXJlbmluZV9tZWFuKQpUTl9LeW51cmVuaW5lX21lYW4gPC0gbGVmdF9qb2luKFROX0t5bnVyZW5pbmVfbWVhbiwgZG9yX21ldGEsIGJ5ID0gInNhbXBsZV9uYW1lIikKcm93bmFtZXMoVE5fS3ludXJlbmluZV9tZWFuKSA8LSBUTl9LeW51cmVuaW5lX21lYW4kc2FtcGxlX25hbWUKClROX0t5bnVyZW5pbmVfZml0IDwtIGxtKGRvciB+IGNvbE1lYW5zKFROX0t5bnVyZW5pbmUpLCBkYXRhPSBUTl9LeW51cmVuaW5lX21lYW4pCnN1bW1hcnkoVE5fS3ludXJlbmluZV9maXQpCgpnZ3BfVE5fS3ludXJlbmluZSA8LSBnZ3Bsb3QoVE5fS3ludXJlbmluZV9tZWFuLCBhZXMoeCA9IGNvbE1lYW5zKFROX0t5bnVyZW5pbmUpLCB5ID0gZG9yKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvcj1kb3JfY2xhc3MpKQpnZ3NhdmUoZ2dwX1ROX0t5bnVyZW5pbmUsIGZpbGVuYW1lID0gcGFzdGUoZGlyLCAicGxvdF9vdXQvTkkwOC9UTl9LeW51cmVuaW5lX2J1bGtpemVkLnBkZiIsIHNlcCA9ICIiKSkKYGBgCgpCdWxraXplIGZpdCBhbmFseXNpcyBQbGFzbWlub2dlbgpgYGB7cn0KUGxhc21pbm9nZW5fc2lnIDwtIGMoJ0FOWEEyJywgJ1BMQVQnLCAnUExBVScsICdQTEFVUicpClROX1BsYXNtaW5vZ2VuIDwtIFROLnNhbXBsZS5hdmVyYWdlc1tQbGFzbWlub2dlbl9zaWcsIF0KVE5fUGxhc21pbm9nZW5fbWVhbiA8LSBhcy5kYXRhLmZyYW1lKGNvbE1lYW5zKFROX1BsYXNtaW5vZ2VuKSkKVE5fUGxhc21pbm9nZW5fbWVhbiRzYW1wbGVfbmFtZSA8LSByb3duYW1lcyhUTl9QbGFzbWlub2dlbl9tZWFuKQpUTl9QbGFzbWlub2dlbl9tZWFuIDwtIGxlZnRfam9pbihUTl9QbGFzbWlub2dlbl9tZWFuLCBkb3JfbWV0YSwgYnkgPSAic2FtcGxlX25hbWUiKQpyb3duYW1lcyhUTl9QbGFzbWlub2dlbl9tZWFuKSA8LSBUTl9QbGFzbWlub2dlbl9tZWFuJHNhbXBsZV9uYW1lCgpUTl9QbGFzbWlub2dlbl9maXQgPC0gbG0oZG9yIH4gY29sTWVhbnMoVE5fUGxhc21pbm9nZW4pLCBkYXRhPSBUTl9QbGFzbWlub2dlbl9tZWFuKQpzdW1tYXJ5KFROX1BsYXNtaW5vZ2VuX2ZpdCkKCmdncF9UTl9QbGFzbWlub2dlbiA8LSBnZ3Bsb3QoVE5fUGxhc21pbm9nZW5fbWVhbiwgYWVzKHggPSBjb2xNZWFucyhUTl9QbGFzbWlub2dlbiksIHkgPSBkb3IpKSArIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZG9yX2NsYXNzKSkKZ2dzYXZlKGdncF9UTl9QbGFzbWlub2dlbiwgZmlsZW5hbWUgPSBwYXN0ZShkaXIsICJwbG90X291dC9OSTA4L1ROX1BsYXNtaW5vZ2VuX2J1bGtpemVkLnBkZiIsIHNlcCA9ICIiKSkKYGBgCgpCdWxraXplIGZpdCBhbmFseXNpcyBvZiBTRVJQSU5FMQpgYGB7cn0KVE5fU2VycGluZV9zaWcgPC0gIGFzLmRhdGEuZnJhbWUodChUTi5zYW1wbGUuYXZlcmFnZXNbIlNFUlBJTkUxIiwgXSkpClROX1NlcnBpbmVfc2lnJHNhbXBsZV9uYW1lIDwtIHJvd25hbWVzKFROX1NlcnBpbmVfc2lnKQpUTl9TZXJwaW5lX3NpZyA8LSBsZWZ0X2pvaW4oVE5fU2VycGluZV9zaWcsIGRvcl9tZXRhLCBieSA9ICJzYW1wbGVfbmFtZSIpCnJvd25hbWVzKFROX1NlcnBpbmVfc2lnKSA8LSBUTl9TZXJwaW5lX3NpZyRzYW1wbGVfbmFtZQoKVE5fU2VycGluZV9maXQgPC0gbG0oZG9yIH4gU0VSUElORTEsIGRhdGE9IFROX1NlcnBpbmVfc2lnKQpzdW1tYXJ5KFROX1NlcnBpbmVfZml0KQoKZ2dwX1ROX1NlcnBpbmUxIDwtIGdncGxvdChUTl9TZXJwaW5lX3NpZywgYWVzKHggPSBTRVJQSU5FMSwgeSA9IGRvcikpICsgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBkb3JfY2xhc3MpKQpnZ3NhdmUoZ2dwX1ROX1NlcnBpbmUxLCBmaWxlbmFtZSA9IHBhc3RlKGRpciwgInBsb3Rfb3V0L05JMDgvVE5fU2VycGluZTFfYnVsa2l6ZWQucGRmIiwgc2VwID0gIiIpKQpgYGAKCkJ1bGtpemUgZml0IGFuYWx5c2lzIEdhcEp1bmN0aW9uCmBgYHtyfQpHYXBKdW5jdGlvbl9zaWcgPC0gYygnR0pCMycsICdHSkIyJywgJ0dKQjQnLCdHSkI1JykKVE5fR2FwSnVuY3Rpb24gPC0gVE4uc2FtcGxlLmF2ZXJhZ2VzW0dhcEp1bmN0aW9uX3NpZywgXQpUTl9HYXBKdW5jdGlvbl9tZWFuIDwtIGFzLmRhdGEuZnJhbWUoY29sTWVhbnMoVE5fR2FwSnVuY3Rpb24pKQpUTl9HYXBKdW5jdGlvbl9tZWFuJHNhbXBsZV9uYW1lIDwtIHJvd25hbWVzKFROX0dhcEp1bmN0aW9uX21lYW4pClROX0dhcEp1bmN0aW9uX21lYW4gPC0gbGVmdF9qb2luKFROX0dhcEp1bmN0aW9uX21lYW4sIGRvcl9tZXRhLCBieSA9ICJzYW1wbGVfbmFtZSIpCnJvd25hbWVzKFROX0dhcEp1bmN0aW9uX21lYW4pIDwtIFROX0dhcEp1bmN0aW9uX21lYW4kc2FtcGxlX25hbWUKClROX0dhcEp1bmN0aW9uX2ZpdCA8LSBsbShkb3IgfiBjb2xNZWFucyhUTl9HYXBKdW5jdGlvbiksIGRhdGE9IFROX0dhcEp1bmN0aW9uX21lYW4pCnN1bW1hcnkoVE5fR2FwSnVuY3Rpb25fZml0KQoKZ2dwX1ROX0dhcEp1bmN0aW9uIDwtIGdncGxvdChUTl9HYXBKdW5jdGlvbl9tZWFuLCBhZXMoeCA9IGNvbE1lYW5zKFROX0dhcEp1bmN0aW9uKSwgeSA9IGRvcikpICsgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBkb3JfY2xhc3MpKQpnZ3NhdmUoZ2dwX1ROX0dhcEp1bmN0aW9uLCBmaWxlbmFtZSA9IHBhc3RlKGRpciwgInBsb3Rfb3V0L05JMDgvVE5fR2FwSnVjaW9uX2J1bGtpemVkLnBkZiIsIHNlcCA9ICIiKSkKYGBgCgoKYGBge3J9CmJ1bGtpemVkX1ROX21hcmtlcnMgPC0gcmVhZC5jc3YoZmlsZSA9IHBhc3RlKGRpciwgIkRhdGFfaW5wdXQvbXd1X2x1YWQuY3N2Iiwgc2VwID0gIiIpKQpidWxraXplZF9UTl9tYXJrZXJzLmYgPC0gZmlsdGVyKGJ1bGtpemVkX1ROX21hcmtlcnMsIHB2YWxfMSA8PSAwLjA1KQpoaXN0KGJ1bGtpemVkX1ROX21hcmtlcnMuZiRzdGF0XzEpCmxlbmd0aChidWxraXplZF9UTl9tYXJrZXJzLmYkcHZhbF8xKQpidWxraXplZF9UTl9tYXJrZXJzLmYgPC0gYnVsa2l6ZWRfVE5fbWFya2Vycy5mW29yZGVyKGJ1bGtpemVkX1ROX21hcmtlcnMuZiRzdGF0XzEsIGRlY3JlYXNpbmcgPSBUUlVFKSwgXSAKYGBgCgpgYGB7cn0KdGFibGUoYnVsa2l6ZWRfVE5fbWFya2Vycy5mJHRlc3QpCmBgYAoKTW9zdCBjb21wZWxsaW5nIGhpZ2ggZXhwcmVzc2lvbiBjb3JyIHRvIGxvdyBkb3IKYGBge3J9CmdncGxvdChzYW1wbGUuYXZlcmFnZXMudCwgYWVzKHggPSBBREFSLCB5ID0gZG9yKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHBhdGllbnRfaWQpKQpnZ3Bsb3Qoc2FtcGxlLmF2ZXJhZ2VzLnQsIGFlcyh4ID0gQ0ZMMSwgeSA9IGRvcikpICsgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBwYXRpZW50X2lkKSkKYGBgCgpNb3N0IGNvbXBlbGxpbmcgaGlnaCBleHByZXNzaW9uIGNvcnIgdG8gaGlnaCBkb3IKYGBge3J9CmdncGxvdChzYW1wbGUuYXZlcmFnZXMudCwgYWVzKHggPSBUVExMMTNQLCB5ID0gZG9yKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGRvcl9jbGFzcykpCmdncGxvdChzYW1wbGUuYXZlcmFnZXMudCwgYWVzKHggPSBBTFMyLCB5ID0gZG9yKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGRvcl9jbGFzcykpCmdncGxvdChzYW1wbGUuYXZlcmFnZXMudCwgYWVzKHggPSBSTE4xLCB5ID0gZG9yKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGRvcl9jbGFzcykpCmdncGxvdChzYW1wbGUuYXZlcmFnZXMudCwgYWVzKHggPSBVU1A0NSwgeSA9IGRvcikpICsgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBkb3JfY2xhc3MpKQpnZ3Bsb3Qoc2FtcGxlLmF2ZXJhZ2VzLnQsIGFlcyh4ID0gQkRLUkIxLCB5ID0gZG9yKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGRvcl9jbGFzcykpCmdncGxvdChzYW1wbGUuYXZlcmFnZXMudCwgYWVzKHggPSBMSU5DMDEwNjEsIHkgPSBkb3IpKSArIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZG9yX2NsYXNzKSkKZ2dwbG90KHNhbXBsZS5hdmVyYWdlcy50LCBhZXMoeCA9IFpORjU2MywgeSA9IGRvcikpICsgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBkb3JfY2xhc3MpKQpnZ3Bsb3Qoc2FtcGxlLmF2ZXJhZ2VzLnQsIGFlcyh4ID0gV0RSMTksIHkgPSBkb3IpKSArIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZG9yX2NsYXNzKSkKYGBgCgo=